package venus

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"net/url"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var (
	PASWD              = "dGxzOi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFbVRDQ0E0R2dBd0lCQWdLQ0FRQlZGbm1Ja3lhVGcrUXR3S2d6aHhjVE9MdDlvZnl3alNMS01XL2YwSlFQCm1md0x1b3gzc08yc0hKK2FHaHhCYTVINkhOaXl5TitTMmlkck55OVNnRi80WiswMUl2c29NbVBDVzdwblhrZTgKQXg4LzVUTWJUV3VXM0FxamRTZHZXdjlIMkI1NExYSXk5WkJVdUl3U3pJMW90cmZrNFh1N2xNa01sS0Q1dk9IQgpxWWtOVDY4cEl6VTVNTFZoWVN4bUNSRnI1dkhvbXJYWUVCejBPTU1ZcHlqRjBrajNzZks1Zlh3NDdsclo1VnpPClFOZURhajIrZWlaUWVNWWYvaWVHTHpza0VPRUYvdUc4dGxaN052RUUxdTdhd0doRmJTQy9xYjhYeWk5b3d5ME4KU2g2Z1ZibUp2SFBrZzVFT1lZRm5lS1ZDZnE0WXpRWnZvVUVzN0drRWZQQ3RNQTBHQ1NxR1NJYjNEUUVCQ3dVQQpNR1V4Q3pBSkJnTlZCQVlUQWtwUU1RNHdEQVlEVlFRSUV3VlViMnQ1YnpFT01Bd0dBMVVFQnhNRlZHOXJlVzh4CkVEQU9CZ05WQkFrVEIxUmhjMk5wYTI4eEVUQVBCZ05WQkJFVENERXdMVEl3TUMwME1SRXdEd1lEVlFRS0V3aEwKWTNCbFpTQkRiekFlRncweU1EQTNNRGd3T0RNM016SmFGdzB5TVRBM01EZ3dPRE0zTXpKYU1HVXhDekFKQmdOVgpCQVlUQWtwUU1RNHdEQVlEVlFRSUV3VlViMnQ1YnpFT01Bd0dBMVVFQnhNRlZHOXJlVzh4RURBT0JnTlZCQWtUCkIxUmhjMk5wYTI4eEVUQVBCZ05WQkJFVENERXdMVEl3TUMwME1SRXdEd1lEVlFRS0V3aExZM0JsWlNCRGJ6Q0MKQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMdFNHdXVLWGhzVWY0cDNzT2I2QnNBNAo3WCtDRVpJSys2RzZiWFp4V2poSDdCNDI0amdPNS9XZ0ZDbzNySDEwK0FvRU5BRGtBcUUrYjAyTWgzb0d4Wm9QCk5yT0hXeE5Rb2puVlBVd1drMW05NGEra2JIcHNQdHdDd0FnNzBmbTJlNUJKK3ZMNEJEdUsyeEZta1Zub2dpN0kKMDJFWmtDcFdQaU5kMTlaMVdvWmY4MlVCaFBoQ3RyRURGV1NWeW1Vc0lac1Rsa2JWbmJXQzhnMU1Wa2xJdlMxNgp4aGVHa1kyR2hNOEViWUJrZmZ1bzlyT2Fmazh3dTlKT0V5eTFzelIxL3FMZjA0Q0xGa0dMdGRKbnFrSmJaQ2hYCllTRXZqSEpzVkRhMDg1ODZzUGZPckQrRUlsODlyZ1JPalJuWDFGWlBiVW41OW8xN05XTWFTTmtINVdaOU5Ic0MKQXdFQUFhTlRNRkV3RGdZRFZSMFBBUUgvQkFRREFnV2dNQjBHQTFVZEpRUVdNQlFHQ0NzR0FRVUZCd01CQmdncgpCZ0VGQlFjREFqQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BOEdBMVVkRVFRSU1BYUhCSDhBQUFFd0RRWUpLb1pJCmh2Y05BUUVMQlFBRGdnRUJBSnZsODd0RXVQZ3labGZma3BNMzFtK2ZjN2pralUzdjVla0pwWUsreVVDS3B2d0sKSGo3V3ZTdW1oa0cyb0VHTGdKeUh1WEdtT2E3NFp4RWhSY3RRd3VFODM4M0NhYXkrZmczeXQ0NGZPa0ExVzhRSwpKZXQ3K21HeERESVJQM0s3VExvMWdmS09kRFJ5RTc1N0NMeG1mcHNkbngwbWRUQUIyWDgwM05rTmk3TXNka3NPCm5QTmhjQjZyVDc4Q0RTSlpwUkZvK1RTMytEUVQ0c0daT05vSkN1OVhuQ0VPaFk2c0xBb1FxVVl5d0xibVJFaG4KUThXbHFLN1BnTDR3SmViNHRieEwyeWhoelI3TDQ3VGtrb2w1Z0ZNRGRQcGxQZVNSbWdCaG0vSnJaRkN3WFZDUAp2WWVhQlNmdkxid0hUaWVaL1VBVGlyaUVUaGg2WndRVHM5KytYMlE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KPFNFUD4tLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS0KTUlJRXZnSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2d3Z2dTa0FnRUFBb0lCQVFDN1VocnJpbDRiRkgrSwpkN0RtK2diQU9PMS9naEdTQ3Z1aHVtMTJjVm80Uit3ZU51STREdWYxb0JRcU42eDlkUGdLQkRRQTVBS2hQbTlOCmpJZDZCc1dhRHphemgxc1RVS0k1MVQxTUZwTlp2ZUd2cEd4NmJEN2NBc0FJTzlINXRudVFTZnJ5K0FRN2l0c1IKWnBGWjZJSXV5Tk5oR1pBcVZqNGpYZGZXZFZxR1gvTmxBWVQ0UXJheEF4VmtsY3BsTENHYkU1WkcxWjIxZ3ZJTgpURlpKU0wwdGVzWVhocEdOaG9UUEJHMkFaSDM3cVBhem1uNVBNTHZTVGhNc3RiTTBkZjZpMzlPQWl4WkJpN1hTClo2cENXMlFvVjJFaEw0eHliRlEydFBPZk9yRDN6cXcvaENKZlBhNEVUbzBaMTlSV1QyMUorZmFOZXpWakdraloKQitWbWZUUjdBZ01CQUFFQ2dnRUJBSUV2SFl1bFVFTWl2dGF5dHRpRVE5V2JMUWRMbjJ4MWtKWTNxTGdQY21YdwpEQUhHWGZyRkpPbDdiWXl6K294Rzk2eUl1NGlGdHQ2VzNWSEJBY21CRkJPc1BGQlJuOWpST2gvaVZMUzl1UDhoCitad1ZMQTY5eWhnVytYSjBOdG9kSkZnYy9TbEZMRDRZQS82Ykd0RERqY3hRQ1o4a2J3MFRqeVQ2MmhoM3RHZUkKWkkvN2RCeUFTSk1nODZRdlJzaDdiOTJYYVZ3eXM0SHpDcVNDeGVrZDIxVmVSWlQzRnNVSXUzbkptamNZazJVdgo3OWdUQWt1aUNydnpBcG81TzBybnphSEJhUEl6YThUUWdCamJxMnpNT1hCOGsyUktGZUNCY2RId1U5UkIzUlVHCmE1cjhLSFhrS09pK1JKT2s1b0Z1d05hRUo1UkcyVlY2c2lSYTE0ZlM4REVDZ1lFQTNwektlSFpCUzJLVnpURSsKOVR4citTVVBxZlkvZnNNRk9YdEZYSlpkRmhQQnRkSkk5MEllL2N3UDVYeE16VFdzeHBPOENIdVNocU1BbUZyagpGa1pFdWVFQlcwWnVhellGT3dSdkd1YUlsU05RWjdoVHZSRWJ6UXFVSjFwMzBXWjE2LzQyNDMyY0F0NXhTTXUxCmRoZVB1bzF6VFNnbWZmV2pjWFM0SXdkeWg3a0NnWUVBMTJwSmpCanlHbUFlVjhhcHB6Z1dkYm1IblJDazVQNkUKdmJpN3Vid2tta2FVUDByY2ZOaWl2aHB0UUFidWNvMytZVHRyZ3RWYTN2WFkrTTkwd0JxS3NMTk9jR21xWnFIOQppNHVzanI2TGdJYzlMaWo1N2tleklHOVU3UWJDRllaSUtFU24va0pyODVCYW14QUh5cGQyeTB0ZWF2UFI4TU5xCnFteWdaTmovajlNQ2dZRUF3S1Y1Um5RNEgwL3FpWTlqaDRESmcrdkJ1WGtrQzhRam9sSCtmWmlXYUFPaThJRlIKcWNDcjUwRVFSSzJrSFRhbEZaaEY4aVZXY1hOZ2tYaWQ2dW5Xa2ZHWlplNzJvWXMzVFpLUnYvcmZHZ2xjak5YawppY3JqZnpiM2JYTUtHOG9LcExienN6MUJwTzN4cFdpODJieWNJbnBFM1BHeEZmSmNobFBYQW1Gd2lPa0NnWUFRCldqb3hEMmU1aHRobTAyYm5rY05xdG1YTUQ0cGs4OGxCMmJjdWQxRFVBVTJackdZbWVBK0tuTmowUmxKdGtjZmcKdTdFQ29vMmVaVTFPUGZsZjUrUGxYQWMxVTJBaklHTHQ1L0YyZUpLQWRFTzVzRlNndVFLcEVLcUN2OE9WL0xhWApqL2FzdjRBUVlrSHVpWDM5N0JlUmdTd3V0RW1ZbkUwSm1PdG9IR3p5RHdLQmdDNTBtUDNVbzVYUmpYWlQzNnBsClU5SE51UzQ2OW8wcWNFd2d1b1JvUWxUWXp1MXJkT0M1WCtGbEpaWk5kcGczWVVUR0t6cXhGTVpLOVRjNzdnelMKRDV6VWVTQlBhamZiTVJmVHRsZkp2MmhBTEFBeEFWc3FMS3MzVkZPNDM2dGZyVFpQRlZNYWZpRU9OWkFLZ3VxaQpYcFY1OU5DTFdsN1RBUVFSWFRSZDdPNXIKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQpAMTI3LjAuMC4xOjEyMzQ1"
	CENTRY_SERVER_ADDR = ""
)

type Config struct {
	Server       interface{} `json:"server"`
	ServerPort   int         `json:"server_port"`
	LocalPort    int         `json:"local_port"`
	LocalAddress string      `json:"local_address"`
	Password     string      `json:"password"`
	Method       string      `json:"method"` // encryption method

	// following options are only used by server
	PortPassword map[string]string `json:"port_password"`
	Timeout      int               `json:"timeout"`

	// following options are only used by client

	// The order of servers in the client config is significant, so use array
	// instead of map to preserve the order.
	ServerPassword string `json:"server_password"`
}

type TlsConfig struct {
	Ca     x509.CertPool
	Cert   tls.Certificate
	Server string
	priKey rsa.PrivateKey
}

func (tlsConfig *TlsConfig) GenerateConfig() (config tls.Config) {
	// tlsConfig.Ca.AppendCertsFromPEM(tlsConfig.Cert.)
	config = tls.Config{
		Certificates: []tls.Certificate{tlsConfig.Cert},
		// ClientAuth:   tls.RequireAndVerifyClientCert,
		ClientCAs: &tlsConfig.Ca,
	}
	config.Rand = rand.Reader
	return
}

func SetPaswd(pas string) {
	PASWD = pas
}

// func (tlsConfig *TlsConfig) WithConn() (conn *tls.Conn, err error) {
// 	config := tls.Config{
// 		Certificates:       []tls.Certificate{tlsConfig.Cert},
// 		InsecureSkipVerify: true,
// 	}
// 	serverAddress := tlsConfig.Server
// 	conn, err = tls.Dial("tcp", serverAddress, &config)
// 	if err != nil {
// 		log.Println("tls connect:", serverAddress)
// 		return
// 	}
// 	state := conn.ConnectionState()
// 	// for _, v := range state.PeerCertificates {
// 	// 	log.Print(x509.MarshalPKIXPublicKey(v.PublicKey))
// 	// }
// 	if !state.HandshakeComplete {
// 		return nil, errors.New("Not TLS Handleshare finished!!")
// 	}

// 	return
// }

func (tlsConfig *TlsConfig) WithTlsListener() (listenr net.Listener, err error) {
	config := tlsConfig.GenerateConfig()
	listenr, err = tls.Listen("tcp", tlsConfig.Server, &config)
	return
}

func ReadFromFileToTlsConfig(pem, key string) (tlsConf *TlsConfig) {
	tlsConf = new(TlsConfig)
	tlsConf.Server = HostAddr

	pembuf, err := ioutil.ReadFile(pem)
	if err != nil {
		pembuf = []byte(`-----BEGIN CERTIFICATE-----
MIIEmTCCA4GgAwIBAgKCAQBVFnmIkyaTg+QtwKgzhxcTOLt9ofywjSLKMW/f0JQP
mfwLuox3sO2sHJ+aGhxBa5H6HNiyyN+S2idrNy9SgF/4Z+01IvsoMmPCW7pnXke8
Ax8/5TMbTWuW3AqjdSdvWv9H2B54LXIy9ZBUuIwSzI1otrfk4Xu7lMkMlKD5vOHB
qYkNT68pIzU5MLVhYSxmCRFr5vHomrXYEBz0OMMYpyjF0kj3sfK5fXw47lrZ5VzO
QNeDaj2+eiZQeMYf/ieGLzskEOEF/uG8tlZ7NvEE1u7awGhFbSC/qb8Xyi9owy0N
Sh6gVbmJvHPkg5EOYYFneKVCfq4YzQZvoUEs7GkEfPCtMA0GCSqGSIb3DQEBCwUA
MGUxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEOMAwGA1UEBxMFVG9reW8x
EDAOBgNVBAkTB1Rhc2Npa28xETAPBgNVBBETCDEwLTIwMC00MREwDwYDVQQKEwhL
Y3BlZSBDbzAeFw0yMDA3MDgwODM3MzJaFw0yMTA3MDgwODM3MzJaMGUxCzAJBgNV
BAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEOMAwGA1UEBxMFVG9reW8xEDAOBgNVBAkT
B1Rhc2Npa28xETAPBgNVBBETCDEwLTIwMC00MREwDwYDVQQKEwhLY3BlZSBDbzCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtSGuuKXhsUf4p3sOb6BsA4
7X+CEZIK+6G6bXZxWjhH7B424jgO5/WgFCo3rH10+AoENADkAqE+b02Mh3oGxZoP
NrOHWxNQojnVPUwWk1m94a+kbHpsPtwCwAg70fm2e5BJ+vL4BDuK2xFmkVnogi7I
02EZkCpWPiNd19Z1WoZf82UBhPhCtrEDFWSVymUsIZsTlkbVnbWC8g1MVklIvS16
xheGkY2GhM8EbYBkffuo9rOafk8wu9JOEyy1szR1/qLf04CLFkGLtdJnqkJbZChX
YSEvjHJsVDa08586sPfOrD+EIl89rgROjRnX1FZPbUn59o17NWMaSNkH5WZ9NHsC
AwEAAaNTMFEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZI
hvcNAQELBQADggEBAJvl87tEuPgyZlffkpM31m+fc7jkjU3v5ekJpYK+yUCKpvwK
Hj7WvSumhkG2oEGLgJyHuXGmOa74ZxEhRctQwuE8383Caay+fg3yt44fOkA1W8QK
Jet7+mGxDDIRP3K7TLo1gfKOdDRyE757CLxmfpsdnx0mdTAB2X803NkNi7MsdksO
nPNhcB6rT78CDSJZpRFo+TS3+DQT4sGZONoJCu9XnCEOhY6sLAoQqUYywLbmREhn
Q8WlqK7PgL4wJeb4tbxL2yhhzR7L47Tkkol5gFMDdPplPeSRmgBhm/JrZFCwXVCP
vYeaBSfvLbwHTieZ/UATiriEThh6ZwQTs9++X2Q=
-----END CERTIFICATE-----`)
	}
	keybuf, err := ioutil.ReadFile(key)
	if err != nil {
		keybuf = []byte(`-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7Uhrril4bFH+K
d7Dm+gbAOO1/ghGSCvuhum12cVo4R+weNuI4Duf1oBQqN6x9dPgKBDQA5AKhPm9N
jId6BsWaDzazh1sTUKI51T1MFpNZveGvpGx6bD7cAsAIO9H5tnuQSfry+AQ7itsR
ZpFZ6IIuyNNhGZAqVj4jXdfWdVqGX/NlAYT4QraxAxVklcplLCGbE5ZG1Z21gvIN
TFZJSL0tesYXhpGNhoTPBG2AZH37qPazmn5PMLvSThMstbM0df6i39OAixZBi7XS
Z6pCW2QoV2EhL4xybFQ2tPOfOrD3zqw/hCJfPa4ETo0Z19RWT21J+faNezVjGkjZ
B+VmfTR7AgMBAAECggEBAIEvHYulUEMivtayttiEQ9WbLQdLn2x1kJY3qLgPcmXw
DAHGXfrFJOl7bYyz+oxG96yIu4iFtt6W3VHBAcmBFBOsPFBRn9jROh/iVLS9uP8h
+ZwVLA69yhgW+XJ0NtodJFgc/SlFLD4YA/6bGtDDjcxQCZ8kbw0TjyT62hh3tGeI
ZI/7dByASJMg86QvRsh7b92XaVwys4HzCqSCxekd21VeRZT3FsUIu3nJmjcYk2Uv
79gTAkuiCrvzApo5O0rnzaHBaPIza8TQgBjbq2zMOXB8k2RKFeCBcdHwU9RB3RUG
a5r8KHXkKOi+RJOk5oFuwNaEJ5RG2VV6siRa14fS8DECgYEA3pzKeHZBS2KVzTE+
9Txr+SUPqfY/fsMFOXtFXJZdFhPBtdJI90Ie/cwP5XxMzTWsxpO8CHuShqMAmFrj
FkZEueEBW0ZuazYFOwRvGuaIlSNQZ7hTvREbzQqUJ1p30WZ16/42432cAt5xSMu1
dhePuo1zTSgmffWjcXS4Iwdyh7kCgYEA12pJjBjyGmAeV8appzgWdbmHnRCk5P6E
vbi7ubwkmkaUP0rcfNiivhptQAbuco3+YTtrgtVa3vXY+M90wBqKsLNOcGmqZqH9
i4usjr6LgIc9Lij57kezIG9U7QbCFYZIKESn/kJr85BamxAHypd2y0teavPR8MNq
qmygZNj/j9MCgYEAwKV5RnQ4H0/qiY9jh4DJg+vBuXkkC8QjolH+fZiWaAOi8IFR
qcCr50EQRK2kHTalFZhF8iVWcXNgkXid6unWkfGZZe72oYs3TZKRv/rfGglcjNXk
icrjfzb3bXMKG8oKpLbzsz1BpO3xpWi82bycInpE3PGxFfJchlPXAmFwiOkCgYAQ
WjoxD2e5hthm02bnkcNqtmXMD4pk88lB2bcud1DUAU2ZrGYmeA+KnNj0RlJtkcfg
u7ECoo2eZU1OPflf5+PlXAc1U2AjIGLt5/F2eJKAdEO5sFSguQKpEKqCv8OV/LaX
j/asv4AQYkHuiX397BeRgSwutEmYnE0JmOtoHGzyDwKBgC50mP3Uo5XRjXZT36pl
U9HNuS469o0qcEwguoRoQlTYzu1rdOC5X+FlJZZNdpg3YUTGKzqxFMZK9Tc77gzS
D5zUeSBPajfbMRfTtlfJv2hALAAxAVsqLKs3VFO436tfrTZPFVMafiEONZAKguqi
XpV59NCLWl7TAQQRXTRd7O5r
-----END PRIVATE KEY-----`)
	}
	crt, err2 := tls.X509KeyPair(pembuf, keybuf)
	if err2 != nil {
		log.Fatal("authentify failed : ", err2)
		// return nil, err2
	}

	tlsConf.Cert = crt
	// tlsConfig.priKey = *key
	tlsConf.Ca = *x509.NewCertPool()
	tlsConf.Ca.AppendCertsFromPEM(pembuf)
	return
}

func (config *Config) ToTlsConfig() (tlsConfig *TlsConfig, err error) {
	if config.Method != "tls" {
		return
	}
	tlsConfig = new(TlsConfig)
	tlsConfig.Server = fmt.Sprintf("%s:%d", config.Server.(string), config.ServerPort)

	// ColorL("raw:", config.Password)
	pems := strings.SplitN(config.Password, "<SEP>", 2)

	pemBlock := []byte(strings.TrimSpace(pems[0]))
	keyBlock := []byte(strings.TrimSpace(pems[1]))

	// preName := ".tmp." + strconv.Itoa(random.Int())

	// ioutil.WriteFile(preName+".pem", pemBlock, os.ModePerm)
	// ioutil.WriteFile(preName+".key", keyBlock, os.ModePerm)
	// defer os.Remove(preName + ".pem")
	// defer os.Remove(preName + ".key")
	// crtx, err2 := x509.ParseCertificate(pemBlock.Bytes)
	// crt, err2 := tls.LoadX509KeyPair(preName+".pem", preName+".key")
	crt, err2 := tls.X509KeyPair(pemBlock, keyBlock)
	if err2 != nil {
		return nil, err2
	}

	tlsConfig.Cert = crt
	// tlsConfig.priKey = *key
	tlsConfig.Ca = *x509.NewCertPool()
	tlsConfig.Ca.AppendCertsFromPEM(pemBlock)
	return
}

func (config *Config) ToString() string {
	return fmt.Sprintf("%s:%d", config.Server.(string), config.ServerPort)
}

func (config *Config) ToFile(dst string) (err error) {
	if f, err := json.Marshal(config); err == nil {
		if err := ioutil.WriteFile(dst, f, 0644); err != nil {
			return err
		}
	} else {
		return err
	}
	return
}

func (config *Config) ToJson() string {
	if f, err := json.Marshal(config); err == nil {
		return string(f)
	}
	return ""
}

func (config *Config) ToUri() string {
	base := fmt.Sprintf("%s:%s@%s:%d", config.Method, config.Password, config.Server.(string), config.ServerPort)
	encoder := base64.StdEncoding.EncodeToString([]byte(base))
	return fmt.Sprintf("ss://%s", encoder)
}

// GetServerArray get server
func (config *Config) GetServerArray() []string {
	// Specifying multiple servers in the "server" options is deprecated.
	// But for backward compatibility, keep this.
	if config.Server == nil {
		return nil
	}
	single, ok := config.Server.(string)
	if ok {
		return []string{single}
	}
	arr, ok := config.Server.([]interface{})
	if ok {
		serverArr := make([]string, len(arr), len(arr))
		for i, s := range arr {
			serverArr[i], ok = s.(string)
			if !ok {
				goto typeError
			}
		}
		return serverArr
	}
typeError:
	panic(fmt.Sprintf("Config.Server type error %v", reflect.TypeOf(config.Server)))
}

// ParseConfig parse path to json
func ParseConfig(path string) (config *Config, err error) {
	file, err := os.Open(path) // For read access.
	if err != nil {
		return
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return
	}

	config = &Config{}
	if err = json.Unmarshal(data, config); err != nil {
		return nil, err
	}
	config.Timeout = 5000
	return
}

// UpdateConfig : Useful for command line to override options specified in config file  Debug is not updated.
func UpdateConfig(old, new *Config) {
	// Using reflection here is not necessary, but it's a good exercise.
	// For more information on reflections in Go, read "The Laws of Reflection"
	// http://golang.org/doc/articles/laws_of_reflection.html
	newVal := reflect.ValueOf(new).Elem()
	oldVal := reflect.ValueOf(old).Elem()

	// typeOfT := newVal.Type()
	for i := 0; i < newVal.NumField(); i++ {
		newField := newVal.Field(i)
		oldField := oldVal.Field(i)
		// log.Printf("%d: %s %s = %v\n", i,
		// typeOfT.Field(i).Name, newField.Type(), newField.Interface())
		switch newField.Kind() {
		case reflect.Interface:
			if fmt.Sprintf("%v", newField.Interface()) != "" {
				oldField.Set(newField)
			}
		case reflect.String:
			s := newField.String()
			if s != "" {
				oldField.SetString(s)
			}
		case reflect.Int:
			i := newField.Int()
			if i != 0 {
				oldField.SetInt(i)
			}
		}
	}

	old.Timeout = new.Timeout

}

func GetMainDomain(urlOrHost string) string {
	host := urlOrHost
	if strings.HasPrefix(urlOrHost, "http") {
		u, _ := url.Parse(urlOrHost)
		host = u.Host
	}
	dotCount := strings.Count(host, ".")
	if dotCount > 1 {
		return strings.Join(strings.Split(host, ".")[dotCount-1:], ".")
	} else {
		return host
	}
}

func ParseURI(u string) (config *Config) {
	config = new(Config)
	_, err := parseURI(u, config)
	if err != nil {
		log.Fatal("parse config:", err)
	}
	return
}

func parseURI(u string, cfg *Config) (string, error) {
	if u == "" {
		return "", nil
	}
	invalidURI := errors.New("invalid URI")
	// ss://base64(method:password)@host:port
	// ss://base64(method:password@host:port)
	u = strings.TrimLeft(u, "ss://")
	i := strings.IndexRune(u, '@')
	var headParts, tailParts [][]byte
	if i == -1 {
		dat, err := base64.StdEncoding.DecodeString(u)
		if err != nil {
			return "", err
		}
		parts := bytes.Split(dat, []byte("@"))
		if len(parts) != 2 {
			return "", invalidURI
		}
		headParts = bytes.SplitN(parts[0], []byte(":"), 2)
		tailParts = bytes.SplitN(parts[1], []byte(":"), 2)

	} else {
		if i+1 >= len(u) {
			return "", invalidURI
		}
		tailParts = bytes.SplitN([]byte(u[i+1:]), []byte(":"), 2)
		dat, err := base64.StdEncoding.DecodeString(u[:i])
		if err != nil {
			return "", err
		}
		headParts = bytes.SplitN(dat, []byte(":"), 2)
	}
	if len(headParts) != 2 {
		return "", invalidURI
	}

	if len(tailParts) != 2 {
		return "", invalidURI
	}
	cfg.Method = string(headParts[0])

	cfg.Password = string(headParts[1])
	p, e := strconv.Atoi(string(tailParts[1]))
	if e != nil {
		return "", e
	}
	cfg.Server = string(tailParts[0])
	cfg.ServerPort = p
	return string(tailParts[0]), nil

}

func (tlsConfig *TlsConfig) WithConn() (conn *tls.Conn, err error) {
	config := tls.Config{
		Certificates:       []tls.Certificate{tlsConfig.Cert},
		InsecureSkipVerify: true,
	}
	serverAddress := tlsConfig.Server
	conn, err = tls.Dial("tcp", tlsConfig.Server, &config)
	if err != nil {
		log.Println("tls connect:", serverAddress)
		return
	}
	state := conn.ConnectionState()
	// for _, v := range state.PeerCertificates {
	// 	log.Print(x509.MarshalPKIXPublicKey(v.PublicKey))
	// }
	if !state.HandshakeComplete {
		return nil, errors.New("Not TLS Handleshare finished!!")
	}
	return
}

func UseDefaultTlsConfig(addr string) (tlsConfig *TlsConfig) {
	config := ParseURI(PASWD)

	ts := strings.SplitN(addr, ":", 2)
	config.Server = ts[0]
	if len(ts) == 1 {
		config.ServerPort = 80
	} else {
		config.ServerPort, _ = strconv.Atoi(ts[1])
	}
	tlsConfig, err := config.ToTlsConfig()

	// fmt.Println(tlsConfig)
	if err != nil {
		log.Fatal("Create tls config failed: ", err)
	}
	return
}

func SplitAddr(addr string) (h string, port int) {
	ts := strings.SplitN(addr, ":", 2)
	h = ts[0]
	port, _ = strconv.Atoi(ts[1])
	return
}

func CreateCertificate(serverHost string, isCA bool) (configUri, base string) {
	ps := strings.SplitN(serverHost, ":", 2)
	host := ps[0]
	// hostPort := ps[1]
	if len(host) == 0 {
		log.Fatalf("Missing required --host parameter")
	}

	// var priv interface{}
	var err error
	validFor := 365 * 24 * time.Hour
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey
	if err != nil {
		log.Fatalf("Failed to generate private key: %v", err)
	}

	var notBefore time.Time
	notBefore = time.Now()

	notAfter := notBefore.Add(validFor)

	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 2048)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	if err != nil {
		log.Fatalf("Failed to generate serial number: %v", err)
	}

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization:  []string{"Co"},
			Country:       []string{"JP"},
			Province:      []string{"Tokyo"},
			Locality:      []string{"Tokyo"},
			StreetAddress: []string{"Tasciko"},
			PostalCode:    []string{"10-200-4"},
		},
		NotBefore:             notBefore,
		NotAfter:              notAfter,
		IsCA:                  true,
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
		BasicConstraintsValid: true,
	}

	hosts := strings.Split(host, ",")
	for _, h := range hosts {
		if ip := net.ParseIP(h); ip != nil {
			template.IPAddresses = append(template.IPAddresses, ip)
		} else {
			template.DNSNames = append(template.DNSNames, h)
		}
	}

	if isCA {
		template.IsCA = true
		template.KeyUsage |= x509.KeyUsageCertSign
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv)
	if err != nil {
		log.Fatalf("Failed to create certificate: %v", err)
	}

	certOut := bytes.NewBuffer([]byte{})
	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
		log.Fatalf("Failed to write data to cert.pem: %v", err)
	}

	// log.Print("wrote cert.pem\n")

	keyOut := bytes.NewBuffer([]byte{})
	if err != nil {
		log.Fatalf("Failed to open key.pem for writing: %v", err)
		return
	}
	privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
	if err != nil {
		log.Fatalf("Unable to marshal private key: %v", err)
	}
	if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
		log.Fatalf("Failed to write data to key.pem: %v", err)
	}

	// log.Print("wrote key.pem\n")
	password := fmt.Sprintf("%s<SEP>%s", certOut.String(), keyOut.String())
	base = fmt.Sprintf("%s:%s@%s", "tls", password, serverHost)
	ssBody := base64.StdEncoding.EncodeToString([]byte(base))
	configUri = fmt.Sprintf("%s", ssBody)
	return
}

func TlsFoward(fr net.Conn, server string, raw []byte) {
	dstCon, err := UseDefaultTlsConfig(server).WithConn()
	if err != nil {
		log.Println("connect forward error:", err)
		return
	}
	_, err = dstCon.Write(raw)
	if err != nil {
		log.Println("forawrd err:", err)
		fr.Close()
		return
	}
	Pipe(fr, dstCon)
}

// Base -=-------------------------------------------------------------------------------------
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(io.WriterTo); ok {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(io.ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	// fallback to standard io.CopyBuffer
	buf := make([]byte, 8192)
	return io.CopyBuffer(dst, src, buf)
}

func Pipe(p1, p2 io.ReadWriteCloser) {
	// start tunnel & wait for tunnel termination
	streamCopy := func(dst io.WriteCloser, src io.ReadCloser) {
		// startAt := time.Now()
		Copy(dst, src)
		p1.Close()
		p2.Close()
	}
	go streamCopy(p1, p2)
	streamCopy(p2, p1)
}
